package control;

import java.awt.Image;
import java.io.Serializable;
import java.util.*;

import javax.swing.ImageIcon;

import model.Figure;
import model.Player;

import view.fieldPositions;


/**
 * Player Control
 * 
 * Class for taking care of the players
 * creates new players and adds them to a list
 * as well as keeping track of the number of players
 * 
 * @author Thomas
 *
 */

public class PlayerControl implements IPlayerControl, Serializable
{
	private static final long serialVersionUID = 1L;
	private ArrayList<Player> playerList;
	private Player newPlayer;
	private int numberOfPlayers;
	private int activePlayer;
	private final int goMoney = 4000; 
	private Figure dog = new Figure("dog", "images/dog.png");
	private Figure ship = new Figure("ship", "images/ship.png");
	private Figure hat = new Figure("hat", "images/hat.png");
	private Figure cannon = new Figure("cannon", "images/cannon.png");
	private Figure car = new Figure("car", "images/car.png");
	private Figure iron = new Figure("iron", "images/iron.png");
	
	private ArrayList<Figure> figuresList;
		
	private int[][][] positions = fieldPositions.fieldPositions;
	
	private int startMoney = 30000;
	
	public PlayerControl()
	{
		playerList = new ArrayList<Player>();
		numberOfPlayers = 0;
		figuresList = new ArrayList<Figure>();
		
		figuresList.add(dog);
		figuresList.add(ship);
		figuresList.add(hat);
		figuresList.add(cannon);
		figuresList.add(car);
		figuresList.add(iron);		
	}
	
	/**
	 * Sets the start money for a Player before a player is built.
	 * @param desiredStartMoney Start Money you like to set.
	 */
	public void setStartMoney(int desiredStartMoney)
	{
		this.startMoney = desiredStartMoney;
	}
	
	/**
	 * Gets the start money for a Player before a player is built.
	 * @return StartMoney you like to see.
	 */
	public int getStartMoney()
	{
		return this.startMoney;
	}
	
	
	/**
	 * Method to create a new player
	 * 
	 * @param name name of the new Player
	 * @param startField the starting Field of the Player
	 */	
	public void createPlayer(String name, int startField, boolean human, ImageIcon figure)
	{
		boolean playerAdded = false;
		int x, y;
		
		x = positions[0][numberOfPlayers][0];
		y = positions[0][numberOfPlayers][1];
		
		newPlayer = new Player(name, startField, this.startMoney, human, figure, x, y);
		playerList.add(newPlayer);
		numberOfPlayers++;
		playerAdded = true;
		System.out.println("Player added");
		
		if(playerAdded == false)
			System.out.println("Player not added");
		
	}	
	
	/**
	 * Method to get the number of Players
	 * @return The number of Players in the game
	 */
	public int getNumberOfPlayers()
	{
		return numberOfPlayers;
	}
	
	/**
	 * Method for returning a List of the Players
	 * @return The Players in form of an ArrayList
	 */
	public ArrayList<Player> getPlayerList()
	{
		return playerList;
	}
	
	/**
	 * Checks if a street has a mortgage on it.
	 * @param id The index of the street which become tested.
	 * @param playerNumber The number of the player who is on turn.
	 * @return True if the street has a mortgage. False if it hasn't one.
	 */
	public boolean hasMortgage(int id, int playerNumber)
	{
		//Variables
		ArrayList<Integer> mortgageList;
		
		mortgageList = playerList.get(playerNumber).getMortgageList();
		
		if (true == mortgageList.contains(id)) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Removes a player from the Player list
	 * 
	 * @param player - The Player to remove
	 */
	public void removePlayer(int player)
	{
		//playerList.get(player).setAlive(false);
		playerList.get(player).removeAllMortgages();
		//playerList.get(player).destroy();

		playerList.remove(player);
		numberOfPlayers--;
	}
	
	/**
	 * 
	 * Function within the PlayerControll to move a Player
	 * @param player Player to be moved
	 * @param destination Amount of Fields the Player should be moved forward
	 * @param directField if true the player is moved directly to the field, otherwise the destination will be added to the current Field
	 */
	public void move(int player, int destination, boolean directField)
	{		
		Player currPlayer = playerList.get(player);
		
		if(directField == true)
		{
			currPlayer.move(destination);
			setX(player, positions[destination][player][0]);
			setY(player, positions[destination][player][1]);
			
			if(destination == 0)
			{
				playerList.get(player).addMoney(goMoney);
				GameControl.getControlInstance().addLogEntry(getPlayerName(getActivePlayer()) + ": " +  "4000 Los-Geld kassiert");
			}
		}
		else
		{
			int next = currPlayer.getCurrentField() + destination;
			
			if(next > 39)
			{
				next -= 40;
				currPlayer.addMoney(goMoney);
				GameControl.getControlInstance().addLogEntry(getPlayerName(getActivePlayer()) + ": " +  "4000 Los-Geld kassiert");
			}
			else if(next < 0)
			{
				next+=40;
			}
			
			currPlayer.move(next);
			
			setX(player, positions[next][player][0]);
			setY(player, positions[next][player][1]);
		}
		
	}		
	
	/**
	 * This function returns the Jail-status of the player
	 * @param player - the Player whose status should be checked
	 * @return the Jail Status of the Player
	 */
	public int getJailStatus(int player)
	{
		return playerList.get(player).getJailStatus();
	}
	
	/**
	 * set the jail status of the player
	 * @param player the player
	 * @param jailStatus the status
	 */
	public void setJailStatus(int player, int jailStatus)
	{
		playerList.get(player).setJailStatus(jailStatus);
	}
	
	/**
	 * Returns the Name of the Player with the specified index
	 * @param player
	 * @return the Player Name
	 */
	public String getPlayerName(int player)
	{
		return playerList.get(player).getName();
	}
	
	/**
	 * Returns the Budget of the Player with the specified index
	 * @param player
	 * @return The Budget of the Player
	 */	
	public int getPlayerBudget(int player)
	{
		return playerList.get(player).getMoney();
	}
	
	/**
	 * Returns the Image of the Player with the specified index
	 * @param player
	 * @return The Image of the Player
	 */
	public ImageIcon getPlayerImage(int player)
	{
		return playerList.get(player).getImage();
	}
	
	/**
	 * This function sets the Alive Status of the Player according to the specified boolean value
	 * @param player - The Player whose status should be changed
	 * @param status - The new Alive Status of the Player. 
	 */	
	public void setAliveStatus(int player, boolean status)
	{
		playerList.get(player).setAlive(status);
	}
	
	
	/**
	 * check if the player is alive
	 * @param player the player
	 * @return the alive status of the player
	 */
	public boolean getAliveStatus(int player)
	{
		return playerList.get(player).isAlive(); 
	}
	
	/**
	 * Returns the current Field of the Player with the specified index
	 * @param player - The Player 
	 * @return The current Field
	 */
	public int getCurrentField(int player)
	{
		return playerList.get(player).getCurrentField();
	}

	
	/**
	 * 
	 * @return returns the ActivePlayer
	 */
	public int getActivePlayer()
	{
		return activePlayer;
	}
	
	/**
	 * Returns the index to a player's name.
	 * @param playerName Name of the player.
	 * @return The number
	 */
	public int getPlayerNumber(String playerName)
	{
		int number = -1;
		for(int i = 0; i<getNumberOfPlayers(); i++)
		{
			if(getPlayerName(i).equals(playerName))
			{
				number = i;
			}
		}
		return number;
	}
	
	
	/**
	 * Method for setting the active Player
	 * @param player - the Player to set as the active Player
	 */
	public void setActivePlayer(int player)
	{
		this.activePlayer = player;
	}

	/**
	 * Method for adding Money
	 * @param player - The Player whose budget gets incremented
	 * @param money - The amount of money
	 */
	public void addMoney(int player, int money)
	{
		playerList.get(player).addMoney(money);
	}
	
	
	/**
	 * Method for subtracting Money from a Player
	 * @param player - The Player whose budget gets decremented
	 * @param money - The amount of Money
	 */
	public void subtractMoney(int player, int money)
	{
		playerList.get(player).subtractMoney(money);
	}
	
	/**
	 * Method for adding a mortgage for a player
	 * @param player - The Player that wants to use a mortgage on his property
	 * @param street - The property
	 */
	public void addMortgage(int player, int street)
	{
		playerList.get(player).addMortgage(street);
	}
	
	/**
	 * Method for removing a Mortgage
	 * @param player - The player that paid up his/her mortgage
	 * @param street - The street that was debited with a mortgage
	 */	
	public void removeMortgage(int player, int street)
	{
		playerList.get(player).removeMortgage(street);
	}
	
	/**
	 *
	 * @param player - the player
	 * @return True if the player is a human player or false if it is controlled by AI
	 */	
	public boolean isHuman(int player)
	{
		return playerList.get(player).isHuman();
	}
	
	
	/**
	 * Sets the player to be human or computer
	 * @param player
	 * @param human true if it is a human player or false if it is a computer
	 */
	public void setHuman(int player, boolean human)
	{
		playerList.get(player).setHuman(human);
	}

	
	
	/**
	 * Method for adding a Get out of Jail Card
	 * @param player the player who gains the get out of Jail Card
	 */	
	public void addJailFreeCard(int player) 
	{
		playerList.get(player).addJailFreeCard();
	}
	
	/**
	 * @param player the player who used a jailFreeCard
	 */
	public void removeJailFreeCard(int player)
	{
		if(playerList.get(player).getJailFreeCard() > 0)
			playerList.get(player).removeJailFreeCard();
	}
	
	/**
	 * Method for checking how many Get out of Jail Cards a certain Player owns.
	 * @param player the player to check
	 * @return How many Get out of Jail Cards the player owns
	 */
	public int getJailFreeCard(int player) 
	{	
		return playerList.get(player).getJailFreeCard();
	}
	
	/**
	 * get the x value of the player
	 * @param player the player
	 * @return the x coordinate
	 */
	public int getX(int player)
	{
		return playerList.get(player).getX();
	}
	
	/**
	 * get the y coordinate of the player
	 * @param player the player
	 * @return playerList.get(player).getY() returns the y coordinate of the player 
	 */
	public int getY(int player)
	{
		return playerList.get(player).getY();
	}
	
	/**
	 * set the x coordinate of the player
	 * @param player the player
	 * @param x new x 
	 */
	public void setX(int player, int x)
	{
		playerList.get(player).setX(x);
	}
	
	/**
	 * set the y coordinate of the player
	 * @param player the player
	 * @param y new y coordinate
	 */
	public void setY(int player, int y)
	{
		playerList.get(player).setY(y);
	}
	
	/**
	 * check if the player has rolled
	 * @param player the player
	 * @return the status
	 */
	public boolean hasRolled(int player)
	{
		return playerList.get(player).hasRolled();
	}
	
	/**
	 * set the rolled status
	 * @param player the player
	 * @param status the status
	 */
	public void setRolled(int player, boolean status)
	{
		playerList.get(player).setRolled(status);
	}
	
	/**
	 * return the richest Player in the game
	 * only counts the cash of the player
	 * (no houses etc count for the calculation)
	 * 
	 * @return the richest player
	 */
	public int getRichestPlayer()
	{
		int rPlayer = 0;
		
		for(int i = 0; i < numberOfPlayers; i++)
		{
			if(playerList.get(i).getMoney() > playerList.get(rPlayer).getMoney())
				rPlayer = i;
		}
		
		return rPlayer;
	}
	
}

